<?php
/**
 * a DataMapper pattern implementation
 * stores objects in database using query templates
 * This file is part of Webappkit, a packages system for PHP web apps
 * @link http://webappkit.net
 * @package webappkit
 * @author J.Ducastel <jeremie@ducastel.name>
 * @license http://opensource.org/licenses/gpl-license.php GNU Public License
 */
class DbMapperTool extends WakTool {

    protected $cfg=array(
        'queries'=>array() // class.action like user.insert, user.getbyid etc
    );

    static function Factory($kit_id,$cfg) {
        return new DbMapperTool($kit_id,$cfg);
    }

    /**
     * gets an object instance from database
     * @param string $class
     * @param array $parameters
     * @param string $query defaults to 'get'
     * @param string $prefix if null will defautl to $class
     * @return object
     */
    public function getObject($class,$parameters=array(),$query='get',$prefix=null) {
        // getting query
        if (!$prefix)
            $prefix=$class;
        $query=strtolower("$prefix.$query");
        $sql=$this->_buildQuery($query,$parameters);
        // getting result
        $result=$this->_executeQuery($sql);
        // building instance
        return $this->_instanceFromResult($class,$result);
    }

    /**
     * get multiple object instances
     * @param string $class
     * @param array $parameters
     * @param string $query defaults to 'get_list'
     * @param string $prefix if null will default to $class
     * @return array
     */
    public function getObjects($class,$parameters=array(),$query='get_list',$prefix=null) {
        // getting query
        if (!$prefix)
            $prefix=$class;
        $query=strtolower("$prefix.$query");
        $sql=$this->_buildQuery($query,$parameters);
        // getting result
        $result=$this->_executeQuery($sql);
        // building instances
        $list=array();
        try {
            while ($instance=&$this->_instanceFromResult($class,$result))
                $list[]=$instance;
        } catch (DbNotFound $e) {
            // end of list
        }
        return $list;
    }

    /**
     * search for query template
     * @todo sanitizing params
     * @param string $id
     * @param array $parameters
     * @return uTpl
     */
    protected function _buildQuery($id,$parameters=array()) {
        if (!isset($this->cfg['queries'][$id])) {
			// print_r($this->cfg);
            throw new Exception("DbMapperTool: no query $id",500);
            return false;
        }
        $tpl=new uTpl($this->cfg['queries'][$id]);
        // do sanitizing here
        return $tpl->render($parameters);
    }

    /**
     * builds an instance from sql result
     * @param string $class
     * @param resource $result
     * @return object
     */
    protected function & _instanceFromResult($class,&$result) {
        if (!$values=mysql_fetch_assoc($result)) {
            throw new DbNotFound("DbMapperTool: no result for ".$this->last_query);
        }
        // deactivate for autoloading ?
        /*if ($check_for_class and !class_exists($class)) {
            throw new Exception("DbMapperTool: class $class missing",500);
        }*/
        $instance=new $class();
        foreach ($values as $key => $value) {
            $instance->$key=$value;
        }
        return $instance;
    }

    /**
     *
     * @param string $sql
     * @return resource
     */
    protected function _executeQuery($sql) {
        $this->last_query=$sql;
        if (!$r=mysql_query($sql)) {
            throw new Exception('DbLinkTool: '.mysql_error().': '.$sql,500);
        }
		return $r;
    }
}

/**
 * exceptions
 */
class DbSqlError extends Exception {
    protected $code=500;
}
class DbNotFound extends Exception {
    protected $code=404;
}
